package com.ea.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.ea.common.constant.BaseNumConstant;
import com.ea.common.enums.BusinessTypeEnums;
import com.ea.common.enums.DeliverStatusEnums;
import com.ea.common.enums.OperationResultCode;
import com.ea.common.enums.SysCfgKeyEnums;
import com.ea.common.exception.ServiceException;
import com.ea.common.util.DateTimeUtils;
import com.ea.common.util.IdWorker;
import com.ea.common.util.TypeConversionToJson;
import com.ea.domain.dto.LogisticInfoCallBackOrderDTO;
import com.ea.domain.dto.LogisticInfoDTO;
import com.ea.domain.dto.LogisticLocationDTO;
import com.ea.domain.entity.AreaInfo;
import com.ea.domain.entity.LogisticDetailInfo;
import com.ea.domain.entity.LogisticInfo;
import com.ea.domain.entity.OrderFormInfo;
import com.ea.domain.entity.OrderFormLog;
import com.ea.domain.entity.SysBaseCfg;
import com.ea.domain.query.LogisticQueryDTO;
import com.ea.holder.AdminHolderInfo;
import com.ea.mapper.AreaInfoMapper;
import com.ea.mapper.LogisticDetailInfoMapper;
import com.ea.mapper.LogisticInfoMapper;
import com.ea.mapper.OrderFormInfoMapper;
import com.ea.mapper.OrderFormLogMapper;
import com.ea.service.ILogisticInfoService;
import com.ea.service.ISysBaseCfgService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author NAME-L
 * @Description TODO
 * @className ILogisticInfoServiceImpl
 * @date 2023-01-30 20:48:37
 */
@Service
public class ILogisticInfoServiceImpl implements ILogisticInfoService {

    @Autowired
    private OrderFormInfoMapper orderFormInfoMapper;

    @Autowired
    private ISysBaseCfgService cfgService;

    @Autowired
    private AreaInfoMapper areaInfoMapper;

    @Autowired
    private LogisticInfoMapper logisticInfoMapper;

    @Autowired
    private LogisticDetailInfoMapper detailInfoMapper;

    @Autowired
    private OrderFormLogMapper logMapper;

    @Override
    public void createLogisticInfoBatch(List<Long> orderIdList) {
        if (CollectionUtils.isEmpty(orderIdList)) {
            throw new ServiceException(OperationResultCode.LOGISTIC_CREATE_ERROR);
        }
        SysBaseCfg sysCfg = cfgService.getSysCfgByCfgKey(SysCfgKeyEnums.LOGISTIC_LOCATION);
        // 查询配置文件中设置的默认发货地址
        LogisticLocationDTO locationDTO = TypeConversionToJson.jsonToEntity(sysCfg.getCfgValue(), LogisticLocationDTO.class);
        if (locationDTO == null) {
            throw new ServiceException(OperationResultCode.LOGISTIC_CREATE_ERROR);
        }
        List<OrderFormInfo> orderInfoList = orderFormInfoMapper.selectAllByOrderIdListV2(orderIdList);

        // 存储物流单信息集合
        List<LogisticInfo> logisticInfoList = new ArrayList<>();
        // 存储物流单明细集合
        List<LogisticDetailInfo> logisticDetailInfoList = new ArrayList<>();
        // 回传给发货单，修改信息
        List<LogisticInfoCallBackOrderDTO> callBackOrderInfoList = new ArrayList<>();
        for (OrderFormInfo info : orderInfoList) {
            LogisticLocationDTO receiveAddress = initLogisticLocation(info);
            // 初始化物流信息
            LogisticInfo logisticInfo = initLogisticInfo(info, locationDTO);
            LogisticInfoCallBackOrderDTO callBackOrderDTO = new LogisticInfoCallBackOrderDTO();
            callBackOrderDTO.setOrderId(info.getOrderId());
            callBackOrderDTO.setLogisticNo(logisticInfo.getLogisticNo());
            callBackOrderDTO.setLogisticId(logisticInfo.getLogisticId());
            callBackOrderInfoList.add(callBackOrderDTO);
            List<String> areaList = initLogisticArea(locationDTO, receiveAddress);
            List<AreaInfo> areaInfoList = areaInfoMapper.selectAreaInfoByAreaIdBatch(areaList);
            LocalDateTime nowTime = LocalDateTime.now();
            for (int i = 0; i < areaInfoList.size() - 1; i++) {
                LogisticDetailInfo detailInfo = new LogisticDetailInfo();
                detailInfo.setLogisticId(logisticInfo.getLogisticId());
                detailInfo.setSendFrom(areaInfoList.get(i).getAreaName());
                detailInfo.setSendTo(areaInfoList.get(i + 1).getAreaName());
                detailInfo.setArriveTime(DateTimeUtils.toDate(nowTime));
                logisticDetailInfoList.add(detailInfo);
                nowTime = calculateRandomTime(nowTime);
                if (i + 1 == areaInfoList.size() - 1) {
                    nowTime = calculateRandomTime(nowTime);
                    LogisticDetailInfo endDetailInfo = new LogisticDetailInfo();
                    endDetailInfo.setLogisticId(logisticInfo.getLogisticId());
                    endDetailInfo.setSendFrom(areaInfoList.get(i + 1).getAreaName());
                    endDetailInfo.setSendTo(info.getAddress());
                    endDetailInfo.setArriveTime(DateTimeUtils.toDate(nowTime));
                    logisticDetailInfoList.add(endDetailInfo);
                }
            }
            logisticInfoList.add(logisticInfo);
        }
        if (CollectionUtils.isNotEmpty(logisticInfoList)) {
            logisticInfoMapper.insertLogisticInfoBatch(logisticInfoList);
        }
        if (CollectionUtils.isNotEmpty(logisticDetailInfoList)) {
            detailInfoMapper.insertLogisticDetailBatch(logisticDetailInfoList);
        }
        if (CollectionUtils.isNotEmpty(callBackOrderInfoList)) {
            orderFormInfoMapper.updateCallBackOrder(callBackOrderInfoList);
        }
    }


    @Override
    public LogisticInfoDTO getLogisticDetailInfoList(Long logisticId) {
        LogisticInfo logisticInfo = logisticInfoMapper.selectOneByLogisticId(logisticId);
        if (logisticInfo == null) {
            throw new ServiceException(OperationResultCode.LOGISTIC_NO_EXISTS);
        }
        LogisticInfoDTO logisticInfoDTO = new LogisticInfoDTO();
        logisticInfoDTO.setDeliverMan(logisticInfo.getDeliveryMan());
        logisticInfoDTO.setDeliverPhone(logisticInfo.getDeliveryPhone());
        logisticInfoDTO.setDetailInfoList(detailInfoMapper.selectLogisticDetailListByLogisticId(logisticId));
        return logisticInfoDTO;
    }

    @Override
    public PageInfo<LogisticInfo> getLogisticInfoList(LogisticQueryDTO queryDTO) {
        Integer pageIndex = queryDTO.getPageIndex() == null ? BaseNumConstant.NUM_1 : queryDTO.getPageIndex();
        Integer pageSize = queryDTO.getPageSize() == null ? BaseNumConstant.NUM_20 : queryDTO.getPageSize();
        PageHelper.startPage(pageIndex, pageSize);
        List<LogisticInfo> goodsInfoList = logisticInfoMapper.selectAllByCondition(queryDTO);
        return new PageInfo<>(goodsInfoList);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateLogisticStatus(Long logisticId, Integer status) {
        LogisticInfo logisticInfo = logisticInfoMapper.selectOneByLogisticId(logisticId);
        if (logisticInfo == null) {
            throw new ServiceException(OperationResultCode.LOGISTIC_NO_EXISTS);
        }
        OrderFormInfo orderFormInfo = orderFormInfoMapper.selectOneByOrderId(logisticInfo.getOrderId());
        if (orderFormInfo == null) {
            throw new ServiceException(OperationResultCode.LOGISTIC_NO_MAP_TO_ORDER);
        }

        StringBuilder builder = new StringBuilder();
        OrderFormLog orderFormLog = new OrderFormLog();
        orderFormLog.setLogId(orderFormInfo.getRelId());
        orderFormLog.setOrderId(orderFormInfo.getOrderId());
        builder.append("更新订单物流状态，物流状态由：").append(DeliverStatusEnums.getDeliverStatus(orderFormInfo.getDeliverStatus())).append("变更为：").append(DeliverStatusEnums.getDeliverStatus(status));
        orderFormLog.setLogMsg(builder.toString());
        orderFormLog.setOperator(AdminHolderInfo.getAdminName());
        logisticInfoMapper.updateLogisticStatus(logisticId, status);
        orderFormInfoMapper.updateStatusByType(orderFormInfo.getOrderId(), status, BusinessTypeEnums.DELIVER.getCode());
        logMapper.insertOrderLog(orderFormLog);

    }

    private LogisticLocationDTO initLogisticLocation(OrderFormInfo info) {
        LogisticLocationDTO receiveAddress = new LogisticLocationDTO();
        receiveAddress.setProvinceCode(info.getProvinceCode());
        receiveAddress.setProvince(info.getProvince());
        receiveAddress.setCityCode(info.getCityCode());
        receiveAddress.setCity(info.getCity());
        receiveAddress.setDistrictCode(info.getDistrictCode());
        receiveAddress.setDistrict(info.getDistrict());
        return receiveAddress;
    }


    private LogisticInfo initLogisticInfo(OrderFormInfo info, LogisticLocationDTO locationDTO) {
        LogisticInfo logisticInfo = new LogisticInfo();
        logisticInfo.setOrderId(info.getOrderId());
        logisticInfo.setOrderNo(info.getOrderNo());
        logisticInfo.setLogisticNo(createLogisticsNo());
        logisticInfo.setLogisticId(IdWorker.nextId());
        logisticInfo.setStartPlace(locationDTO.getPlace());
        logisticInfo.setDestination(info.getProvince() + info.getCity() + info.getDistrict());
        logisticInfo.setConsigneePhone(info.getPhone());
        logisticInfo.setDeliveryMan("");
        logisticInfo.setDeliveryPhone("");
        logisticInfo.setSendTime(new Date());
        logisticInfo.setConsigneeName(info.getReceiveName());
        logisticInfo.setAddress(info.getProvince() + info.getCity() + info.getDistrict() + info.getStreet() + info.getAddress());
        return logisticInfo;
    }

    private List<String> initLogisticArea(LogisticLocationDTO normalLocationDTO, LogisticLocationDTO receiveAddress) {
        //发货地点：此处areaCode倒序排列，快递是从 发件所在区-所在市-所在省-收件省-收件市-收件区
        List<String> areaCodeList = new ArrayList<>();
        areaCodeList.add(receiveAddress.getDistrictCode());
        areaCodeList.add(receiveAddress.getCityCode());
        areaCodeList.add(receiveAddress.getProvinceCode());
        areaCodeList.add(normalLocationDTO.getProvinceCode());
        areaCodeList.add(normalLocationDTO.getCityCode());
        areaCodeList.add(normalLocationDTO.getDistrictCode());
        // 去重
        areaCodeList = areaCodeList.stream().distinct().collect(Collectors.toList());
        return areaCodeList;
    }

    private LocalDateTime calculateRandomTime(LocalDateTime dateTime) {
        long randomTime = RandomUtil.randomLong(2, 8);
        long randomMinutesTime = RandomUtil.randomLong(1, 45);
        long randomSecondTime = RandomUtil.randomLong(1, 3600 * 5);
        dateTime = dateTime.plusMinutes(randomMinutesTime);
        dateTime = dateTime.plusSeconds(randomSecondTime);
        dateTime = dateTime.plusHours(randomTime);
        return dateTime;
    }

    /**
     * 随机生成物流单号
     *
     * @return
     */
    public String createLogisticsNo() {
        int randomCount = (int) ((Math.random() * 9 + 1) * 10000);
        Date date = new Date();
        DateFormat dateFormat = new SimpleDateFormat("HHssmmSSS");
        String a = dateFormat.format(date);
        return "L" + a + randomCount;
    }

}
